package yun.web.activerecord.dialect.pg;

import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import yun.web.enjoy.kit.StrKit;
import org.intellij.lang.annotations.Language;
import yun.web.activerecord.generator.ColumnMeta;
import yun.web.activerecord.generator.DataDictionaryGenerator;
import yun.web.activerecord.generator.TableMeta;

import javax.sql.DataSource;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

public class PGDataDictionaryGenerator extends DataDictionaryGenerator {

    Log log = LogFactory.get("PGDataDictionaryGenerator");

    public PGDataDictionaryGenerator(DataSource dataSource, String dataDictionaryOutputDir) {
        super(dataSource, dataDictionaryOutputDir);
    }

    @Override
    protected void rebuildColumnMetas(List<TableMeta> tableMetas) {
        Connection conn = null;
        PreparedStatement pst = null;
        try {
            conn = dataSource.getConnection();
            DatabaseMetaData dbMeta = conn.getMetaData();

            String catalog = dbMeta.getConnection().getCatalog();


            @Language("sql")
            String sql = "select c.table_schema, c.table_name, c.column_name, c.udt_name, c.column_default, pgd.description,c.numeric_precision,c.numeric_scale,c.is_nullable\n" +
                    "from information_schema.columns c\n" +
                    "inner join pg_catalog.pg_statio_all_tables st on c.table_schema = st.schemaname and c.table_name = st.relname\n" +
                    "left join pg_catalog.pg_description pgd on (pgd.objoid = st.relid and pgd.objsubid = c.ordinal_position)\n" +
                    "where 1 = 1\n" +
                    "and c.table_catalog = ?\n" +
                    "and c.table_schema = ?\n" +
                    "and c.table_name = ?\n";

            for (TableMeta it : tableMetas) {

                PGTableMeta tableMeta = (PGTableMeta) it;

                String schema_name = tableMeta.schema_name;
                String table_name = tableMeta.name;

                pst = conn.prepareStatement(sql);
                pst.setString(1, catalog);
                pst.setString(2, schema_name);
                pst.setString(3, table_name);


                // 重建整个 TableMeta.columnMetas
                tableMeta.columnMetas = new ArrayList();
                ResultSet rs = pst.executeQuery();

                while (rs.next()) {
                    ColumnMeta columnMeta = new ColumnMeta();
                    columnMeta.name = rs.getString("column_name");            // 名称

                    columnMeta.type = rs.getString("udt_name");           // 类型
                    if (columnMeta.type == null) {
                        columnMeta.type = "";
                    }

                    columnMeta.isPrimaryKey = "   ";
                    String[] keys = tableMeta.primaryKey.split(",");
                    for (String key : keys) {
                        if (key.equalsIgnoreCase(columnMeta.name)) {
                            columnMeta.isPrimaryKey = "PRI";
                            break;
                        }
                    }

                    columnMeta.defaultValue = rs.getString("COLUMN_DEF");    // 默认值
                    if (columnMeta.defaultValue == null) {
                        columnMeta.defaultValue = "";
                    }

                    columnMeta.remarks = rs.getString("REMARKS");            // 备注
                    if (columnMeta.remarks == null) {
                        columnMeta.remarks = "";
                    }

                    if (tableMeta.colNameMaxLen < columnMeta.name.length()) {
                        tableMeta.colNameMaxLen = columnMeta.name.length();
                    }
                    if (tableMeta.colTypeMaxLen < columnMeta.type.length()) {
                        tableMeta.colTypeMaxLen = columnMeta.type.length();
                    }
                    if (tableMeta.colDefaultValueMaxLen < columnMeta.defaultValue.length()) {
                        tableMeta.colDefaultValueMaxLen = columnMeta.defaultValue.length();
                    }

                    tableMeta.columnMetas.add(columnMeta);
                }
                rs.close();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        } finally {
            if (pst != null) {
                try {
                    pst.close();
                } catch (SQLException e) {
                    log.error(e);
                }
            }
            if (conn != null) {
                try {
                    conn.close();
                } catch (SQLException e) {
                    log.error(e);
                }

            }
        }
    }

    @Override
    protected void generateTable(TableMeta tableMeta, StringBuilder ret) {
        PGTableMeta pgTableMeta = (PGTableMeta) tableMeta;
        String schema_name = pgTableMeta.schema_name;
        schema_name = "_public".equalsIgnoreCase(schema_name) ? "public" : schema_name;
        ret.append("Table: ").append(schema_name)
                .append(".")
                .append(pgTableMeta.name);
        if (StrKit.notBlank(pgTableMeta.remarks)) {
            ret.append("\tRemarks: ").append(pgTableMeta.remarks);
        }
        ret.append("\n");

        String sparateLine = genSeparateLine(pgTableMeta);
        ret.append(sparateLine);
        genTableHead(pgTableMeta, ret);
        ret.append(sparateLine);
        for (ColumnMeta columnMeta : pgTableMeta.columnMetas) {
            genColumn(pgTableMeta, columnMeta, ret);
        }
        ret.append(sparateLine);
        ret.append("\n");
    }
}
